package com.jetpackframework.virtualapk;

import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;

import com.jetpackframework.ContextUtil;
import com.jetpackframework.virtual.VirtualApk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 加载启动插件中的Service
 */
public class ActivityManagerProxy implements InvocationHandler {
    private VirtualInstaller instance;
    private Object activityManager;
    private Method method;

    public ActivityManagerProxy(VirtualInstaller instance, Object activityManager) {
        this.instance = instance;
        this.activityManager = activityManager;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.method = method;
        if (method.getName().equals("startService") || method.getName().equals("stopService") ||
                method.getName().equals("bindService") || method.getName().equals("unbindService")){
            Class<?>[] parameterTypes = method.getParameterTypes();
            parameterTypes[0] = Object.class;
            if (method.getName().equals("bindService")){
                parameterTypes[4] = Object.class;
            }
            return getClass().getMethod(method.getName(),parameterTypes).invoke(this,args);
        }
        return method.invoke(activityManager,args);
    }

    public ComponentName startService(Object applicationThread, Intent intent, String action, int flags) throws InvocationTargetException, IllegalAccessException {
        ComponentName componentName = intent.getComponent();
        VirtualApk apk = instance.getVirtualApk(componentName.getPackageName());
        if (apk != null){
            ServiceInfo serviceInfo = apk.getServiceInfo(componentName);
            if (serviceInfo != null)
                return startServiceDelagateForTarget(intent, serviceInfo, null, RemoteService.EXTRA_COMMAND_START_SERVICE);
        }
        return (ComponentName) method.invoke(activityManager,applicationThread,intent,action,flags);
    }

    public int bindService(Object applicationThread, IBinder iBinder, Intent intent, String action, Object connection, int flags,String string, int i){
        ComponentName componentName = intent.getComponent();
        VirtualApk apk = instance.getVirtualApk(componentName.getPackageName());
        if (apk != null) {
            ServiceInfo serviceInfo = apk.getServiceInfo(componentName);
            if (serviceInfo != null) {
                Bundle bundle = new Bundle();
                bundle.putBinder("sc", (IBinder) connection);
                startServiceDelagateForTarget(intent,serviceInfo,bundle,RemoteService.EXTRA_COMMAND_BIND_SERVICE);
            }
        }
        return 1;
    }
    public int stopService(Object applicationThread,Intent intent,String action,int flags) throws InvocationTargetException, IllegalAccessException {
        ComponentName componentName = intent.getComponent();
        VirtualApk apk = instance.getVirtualApk(componentName.getPackageName());
        if (apk != null){
            ServiceInfo serviceInfo = apk.getServiceInfo(componentName);
            if (serviceInfo != null) {
                startServiceDelagateForTarget(intent, serviceInfo, null, RemoteService.EXTRA_COMMAND_STOP_SERVICE);
                return 1;
            }
        }
        return (int) method.invoke(activityManager,applicationThread,intent,action,flags);
    }
    public boolean unbindService(Object iBinder) throws RemoteException, InvocationTargetException, IllegalAccessException {
        Intent target = instance.forgetServiceConnection((IBinder) iBinder);
        if (target == null) {
            // is host service
            return (boolean) method.invoke(activityManager, iBinder);
        }
        ResolveInfo resolveInfo = instance.getVirtualApk(target.getComponent().getPackageName()).resolveService(target, 0);
        startServiceDelagateForTarget(target, resolveInfo.serviceInfo, null, RemoteService.EXTRA_COMMAND_UNBIND_SERVICE);
        return true;
    }

    private ComponentName startServiceDelagateForTarget(Intent intent, ServiceInfo serviceInfo, Bundle bundle, int command) {
        if (bundle != null){
            intent.putExtras(bundle);
        }
        intent.setComponent(new ComponentName(serviceInfo.packageName,serviceInfo.name));
        Intent targetIntent = new Intent(ContextUtil.get(),RemoteService.class);
        targetIntent.putExtra(RemoteService.EXTRA_COMMAND,command);
        targetIntent.putExtra(RemoteService.EXTRA_INTENT,intent);
        ContextUtil.get().startService(targetIntent);
        return null;
    }
}
